package com.macro.mall.common.exception;

import com.macro.mall.common.enums.BizCode;
import com.macro.mall.common.msg.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;

import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.file.AccessDeniedException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;



/**
 * 统一异常处理的handler
 */
@ControllerAdvice
public class GlobalExceptionHandler {
    //通过日志记录
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);


    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Object returnErrorCode(Throwable exception) {
        StringWriter stringWriter = new StringWriter();
        exception.printStackTrace(new PrintWriter(stringWriter));
        String exceptionDetails = stringWriter.toString();
//        sendWarnningMsg(exceptionDetails);
        return exceptionHandler(exception);
    }

    //表明这个方法处理的是关于exception异常的方法
//    @ExceptionHandler(Exception.class)
//    @ResponseBody
//    public Object handlerException(Exception e){
//        log.error("Default Exception",e);
//        return Result.success(ZjExceptionEnum.SYSTEM_ERROR.getMsg());
//    }

    @ExceptionHandler(ZjException.class)
    @ResponseBody
    public Object handlerMallException(ZjException e){
        log.error("Default Exception",e);
        return Result.success(e.getMessage());
    }

    @ExceptionHandler(BizException.class)
    @ResponseBody
    public ResponseEntity<Object> handleBizException(BizException ex) {
        // 组装返回的错误信息
        Map<String, Object> body = new LinkedHashMap<>();
        body.put("code", ex.getCode());
        body.put("message", ex.getMsg());
        body.put("path", ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getRequestURI());

        // 返回您自定义的状态码而不是500
        return new ResponseEntity<>(body, HttpStatus.valueOf(200));
    }

    @ExceptionHandler(AccessDeniedException.class)
    @ResponseBody
    public ResponseEntity<?> handleAccessDeniedException(AccessDeniedException e) {
        // 构建你的业务返回对象或响应体

        Map<String, Object> body = new LinkedHashMap<>();
        body.put("code", BizCode.NUMBER_200.getCode());
        body.put("message", "权限不足");
        body.put("path", ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getRequestURI());

        return new ResponseEntity<>(body, HttpStatus.valueOf(200));
    }

    public static Result<Void> exceptionHandler(Throwable exception) {
        //业务异常错误
        if (exception instanceof BaseException) {
            BaseException baseException = (BaseException) exception;
            log.info("exception:",exception);
            return Result.failure(String.valueOf(baseException.getStatus()));
        }

        //断言自定义返回值
        //系统参数错误
        if (exception instanceof BizException) {
            log.info("exception:",exception);
            return Result.failure(ExceptionCode.SYSTEM_ERROR.getCode(), exception.getMessage());
        }

        //系统参数错误
        if (exception instanceof IllegalArgumentException) {
            log.info("exception:",exception);
            return Result.failure(ExceptionCode.PARAM_ERROR.getCode(), exception.getMessage());
        }
        //方法参数校验错误
        if (exception instanceof MethodArgumentNotValidException) {
            FieldError fieldError = ((MethodArgumentNotValidException) exception).getBindingResult().getFieldError();
            log.info("exception:",exception);
            return Result.failure(ExceptionCode.PARAM_ERROR.getCode(), fieldError.getDefaultMessage());
        }
        //参数校验错误
        if (exception instanceof ConstraintViolationException) {
            Set<ConstraintViolation<?>> violations = ((ConstraintViolationException) exception).getConstraintViolations();
            StringBuilder builder = new StringBuilder();
            violations.stream().filter(Objects::nonNull).forEach(violation -> builder.append(violation.getMessage()));
            log.info("exception:",exception);
            return Result.failure(ExceptionCode.PARAM_ERROR.getCode(), builder.toString());
        }
        //请求方式错误
        if (exception instanceof HttpRequestMethodNotSupportedException) {
            HttpRequestMethodNotSupportedException ex = (HttpRequestMethodNotSupportedException) exception;
            log.info("exception:",exception);
            return Result.failure(HttpStatus.METHOD_NOT_ALLOWED.value(), String.format("不支持该请求方式(%s)", ex.getMessage()));
        }
        //未传入请求参数错误
        if (exception instanceof HttpMessageNotReadableException) {
            return Result.failure(String.valueOf(ExceptionCode.PARAMS_MISS));
        }
        log.info("exception:",exception);
        return Result.failure(String.valueOf(ExceptionCode.INTERNAL_SERVER_ERROR));
    }

}
